package cn.adelyn.base.gateway.filter;

import cn.adelyn.base.api.auth.feign.TokenFeignClient;
import cn.adelyn.base.api.auth.pojo.AuthUserContext;
import cn.adelyn.base.api.auth.pojo.bo.UserInfoInTokenBO;
import cn.adelyn.base.api.rbac.constant.HttpMethodEnum;
import cn.adelyn.base.api.rbac.feign.PermissionFeignClient;
import cn.adelyn.base.api.rbac.pojo.bo.CheckPermissionBO;
import cn.adelyn.base.gateway.adapter.AuthConfigAdapter;
import cn.adelyn.common.core.response.ResponseEnum;
import cn.adelyn.common.core.response.ServerResponseEntity;
import cn.adelyn.common.feign.util.HttpHandler;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @author chengze
 * @date 2022/12/7
 * @desc 网关做授权卸载，为后面提供免认证环境
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter {
    @Autowired
    private AuthConfigAdapter authConfigAdapter;

    @Autowired
    private TokenFeignClient tokenFeignClient;

    @Autowired
    private PermissionFeignClient permissionFeignClient;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        HttpServletRequest req = (HttpServletRequest) exchange.getRequest();

        List<String> unAuthPatterns = authConfigAdapter.unAuthPatterns();

        // todo 进一步区分方法
        // 如果匹配不需要授权的路径，就不需要校验是否需要授权
        if (CollectionUtil.isNotEmpty(unAuthPatterns)) {
            for (String excludePathPattern : unAuthPatterns) {
                AntPathMatcher pathMatcher = new AntPathMatcher();
                if (pathMatcher.match(excludePathPattern, req.getRequestURI())) {
                    return chain.filter(exchange);
                }
            }
        }

        // 未登录用户没有token，如果没在unAuthPatterns放行，判为未授权访问
        String token = req.getHeader("Authorization");

        if (StrUtil.isBlank(token)) {
            HttpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNLOGIN));
            return chain.filter(exchange);
        }

        // 校验token，并返回用户信息
        ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = tokenFeignClient
                .checkToken(token);
        if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
            HttpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNLOGIN));
            return chain.filter(exchange);
        }

        UserInfoInTokenBO userInfoInToken = userInfoInTokenVoServerResponseEntity.getData();

        // 需要用户角色权限，就去根据用户角色权限判断是否
        if (!checkRbac(userInfoInToken, req.getRequestURI(), req.getMethod())) {
            HttpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED));
            return chain.filter(exchange);
        }

        try {
            // 保存上下文
            AuthUserContext.set(userInfoInToken);

            return chain.filter(exchange);
        } finally {
            AuthUserContext.clean();
        }
    }

    /**
     * 用户角色权限校验
     * @param uri uri
     * @return 是否校验成功
     */
    private boolean checkRbac(UserInfoInTokenBO userInfoInToken, String uri, String method) {

        CheckPermissionBO checkPermissionBO = new CheckPermissionBO();
        checkPermissionBO.setUserType(userInfoInToken.getUserType());
        checkPermissionBO.setUri(uri);
        checkPermissionBO.setMethod(HttpMethodEnum.valueOf(method.toUpperCase()).value());

        ServerResponseEntity<Boolean> booleanServerResponseEntity = permissionFeignClient.checkPermission(checkPermissionBO);

        return booleanServerResponseEntity.isSuccess();
    }
}
